package org.test4j.mock.faking.util;

import g_asm.org.objectweb.asm.Type;

import java.util.HashMap;
import java.util.Map;

import static g_asm.org.objectweb.asm.Type.*;
import static org.test4j.mock.faking.util.TypeDesc.*;

public class AsmType {
    private static Map<Integer, Class> PRIMITIVE_TYPES = new HashMap<>();
    public final static Map<Integer, TypeDesc> PRIMITIVE_OBJECTS = new HashMap<>();

    static {
        PRIMITIVE_TYPES.put(VOID, void.class);
        PRIMITIVE_TYPES.put(BOOLEAN, boolean.class);
        PRIMITIVE_TYPES.put(CHAR, char.class);
        PRIMITIVE_TYPES.put(BYTE, byte.class);
        PRIMITIVE_TYPES.put(SHORT, short.class);
        PRIMITIVE_TYPES.put(INT, int.class);
        PRIMITIVE_TYPES.put(FLOAT, float.class);
        PRIMITIVE_TYPES.put(LONG, long.class);
        PRIMITIVE_TYPES.put(DOUBLE, double.class);

        PRIMITIVE_OBJECTS.put(VOID, T_Void);
        PRIMITIVE_OBJECTS.put(BOOLEAN, T_Boolean);
        PRIMITIVE_OBJECTS.put(CHAR, T_Character);
        PRIMITIVE_OBJECTS.put(BYTE, T_Byte);
        PRIMITIVE_OBJECTS.put(SHORT, T_Short);
        PRIMITIVE_OBJECTS.put(INT, T_Integer);
        PRIMITIVE_OBJECTS.put(FLOAT, T_Float);
        PRIMITIVE_OBJECTS.put(LONG, T_Long);
        PRIMITIVE_OBJECTS.put(DOUBLE, T_Double);
    }

    /**
     * 根据 asm JavaType 获取对应JDK class type
     *
     * @param javaType
     * @return
     */
    public static Class getClassForType(Type javaType) {
        if (isPrimitive(javaType)) {
            return PRIMITIVE_TYPES.get(javaType.getSort());
        } else {
            String className = javaType.getClassName();
            if (javaType.getSort() == ARRAY) {
                className = javaType.getDescriptor().replace("/", ".");
            }
            return ClassLoad.loadClass(className);
        }
    }

    /**
     * asm java type转换为String描述
     *
     * @param javaType
     * @return
     */
    public static String getTypeDesc(Type javaType) {
        if (isReferenceType(javaType)) {
            return javaType.getInternalName();
        } else if (isPrimitive(javaType)) {
            return PRIMITIVE_OBJECTS.get(javaType.getSort()).PATH;
        } else {
            return javaType.getDescriptor();
        }
    }

    public static boolean isPrimitive(Type type) {
        return type.getSort() <= DOUBLE;
    }

    public static boolean isReferenceType(Type type) {
        switch (type.getSort()) {
            case ARRAY:
            case OBJECT:
            case METHOD:
                return true;
            default:
                return false;
        }
    }
}